import 'dart:convert';
import 'dart:io';
import 'package:eshi/app/shi/data/HistoryMarks.dart';
import 'package:eshi/app/utils/FileUtils.dart';
import 'package:eshi/app/utils/PermissionUtils.dart';
import 'package:eshi/app/utils/ZipUtils.dart';
import 'package:file_picker/file_picker.dart';
import 'package:file_selector/file_selector.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:eshi/app/CommonFunctions.dart';
import 'package:eshi/app/shi/data/System.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
class FileParser{
  
  static Future<Map<String, String>> readDirFiles({directoryPath='assets/txt/' }) async{
     Map<String,String>  allTxt =<String,String>{};
     if(kIsWeb){
        for(var name in assets[directoryPath]!){
           allTxt[name.replaceFirst(RegExp(r'\.\w+$'), "")] = "";
        }
        return allTxt;
     }
     final directory = assetsDirectory(directoryPath);
     try {
      // 检查目录是否存在
      if (!await directory.exists()) { 
        // if(System.appDocDir.isNotEmpty){
        //   await copyAssetToWritableDir();
        // } 
        // return readDirFiles();
        return allTxt;
      }
      final entities = directory.listSync(recursive: false)
        .whereType<File>()
        .toList();

      entities.sort((a,b){
            // 获取文件/目录的创建时间
          final aStat = a.statSync();
          final FileStat bStat = b.statSync();
          // 比较创建时间（用millisecondsSinceEpoch便于比较）
          return aStat.changed.compareTo(bStat.changed);
      });
        
      for (var entity in entities) {
          final content = ""; //await entity.readAsString();
          allTxt[entity.path.split("/").last.replaceFirst(RegExp(r'\.\w+$'), "")] = content;
      }
      
    } catch (e) {
      print('读取目录时出错：$e');
    }
    return allTxt;
  }
  static Map<String,List<String>> _assets = {};
  static Map<String, List<String>> get  assets  => _assets;
  static Map<String,String> linkMap ={};
  static initAssets() async{
    final manifestContent = await rootBundle.loadString('AssetManifest.json');
    final Map<String, dynamic> manifestMap = json.decode(manifestContent);
    for(var file in manifestMap.keys){
        if(file.startsWith("assets")){
          var a= file.split("/");
          var key = "${a.sublist(0,2).join("/")}/";
          if(!_assets.containsKey(key)) _assets[key] = [];
          _assets[key]!.add(a[2]);
          if(a[2].endsWith(".link")) linkMap[file] = await assetsloadString(file);
        }
    }
  }

  static void save(String fName, String doc,{directoryPath='assets/txt/' }) async{
      final file = assetsFile(directoryPath+fName);
      if(! await file.exists()) await file.create();
      file.writeAsString(doc);
  }


  /// 获取文件包含扩展名的完整名字
  static String getWholeName(String directoryPath,String name) {
      if(kIsWeb){
        for(var file in assets[directoryPath]!) {
          if(file.startsWith("$name.")){
            var rt = directoryPath + file;
             if(rt.endsWith(".link")){
              // rt = assetsloadString(rt);
              if(linkMap.containsKey(rt)) {
                rt = linkMap[rt]!;
              }
            }
            return rt;
          }
        }
        return "";
      }
      final directory = assetsDirectory(directoryPath);
      var rt = "";
      try{
        final entities = directory.listSync(recursive: false);
        var okFiles = entities
          .whereType<File>()
          .where((File file) {
              return file.path.split("/").last.startsWith("$name.");
          });
          
        rt= okFiles.isNotEmpty ? okFiles.first.path : "";
        if(rt.endsWith(".link")){
          rt = File(rt).readAsStringSync();
        }
      }catch(e){
        print(e.toString());
      }
      return rt;
  }
  static String getAudio(String text,{rootPath = "assets/audio/"}) {
      return getWholeName(rootPath,text);
  }

  //文件内容如果是一个.url文件则读取其中的地址 下载文件到历史目录并返回临时目录地址 
  static String getImage(name,{rootPath = "assets/image/"}) {
      var rt =  getWholeName(rootPath, name);

      return rt;
  }

  static Future<String> getTextContent(name,{rootPath = "assets/txt/",ext=".txt"}) async {
      var file = assetsFile(name.indexOf("/") !=-1 ? name : rootPath+name+ext);
      if(kIsWeb){
         return assetsloadString(file.path);
      }
      if(!await file.exists()) return "";
      return await file.readAsString();
  }
  static File assetsFile(String path){
      return File(path.startsWith("/") ? path : System.appDocDir+path);
  }

  static Future<String> assetsloadString(String path) async{
       return await rootBundle.loadString(path);
  }
  
  static Future<bool> assetsFileExists(String path,{String type="txt"}) async {
      return await File("${System.appDocDir}assets/$type/$path").exists();
  }

  static Directory assetsDirectory(String dir){
      return Directory(System.appDocDir+dir);
  }
  static Future<void> copyAssetToWritableDir() async {
    // 1. 获取可读写目录
    final appDocDir =   await getApplicationDocumentsDirectory();
    for(var v in HistoryMarks.values){
        final targetPath = p.join(appDocDir.path,"assets/${v.name}");
        final targetDir = Directory(targetPath);
        if (!await targetDir.exists()) {
          await targetDir.create(recursive: true);
        }
    }
    // Directory.current;
    final manifestContent = await rootBundle.loadString('AssetManifest.json');
    final Map<String, dynamic> manifestMap    = json.decode(manifestContent);
    for (var name in manifestMap.keys){
        if(!name.startsWith("assets")) continue;
          // 2. 复制 assets 文件
        final assetContent = await rootBundle.load(name);
        final targetPath = p.join(appDocDir.path,name);
        final targetDir = Directory(p.dirname(targetPath));
        if (!await targetDir.exists()) await targetDir.create(recursive: true);
        
        final targetFile = File(targetPath);
        print(targetFile.path);
        await targetFile.writeAsBytes(assetContent.buffer.asUint8List());
    }

    for(var v in HistoryMarks.values){
        final targetPath = p.join(appDocDir.path,"assets/${v.name}");
        final targetDir = Directory(targetPath);
        if (!await targetDir.exists()) {
          await targetDir.create(recursive: true);
        }
    }
  }

  
  //导入一个文件
  static importFile(XFile file) async{
      var type = FileUtils.getMimeType(file);
      var targetFile = assetsFile("assets/$type/${file.name}");
      if(["video","doc","app"].contains(type)) {
        // final targetDir = assetsDirectory("assets/$type");
        // if (!await targetDir.exists()) await targetDir.create(recursive: true);
            // 根据平台选择需要请求的权限
        final p = PermissionUtils.fileRead;
        if(p!=null) System.requestPermission(p);
        int size = await file.length();
        if(size > 10*1048576){
          final name = file.name.substring(0,file.name.lastIndexOf('.'));
          targetFile = assetsFile("assets/$type/$name.link");
          await targetFile.writeAsString(file.path);
          return;
        }
      }
      await targetFile.writeAsBytes(await file.readAsBytes());
  }
     // 选择多个文件
  static Future<void> pickMultipleFiles(Future<void> Function(String name,XFile file) filter) async {
    // final List<XFile> files = await openFiles();   //大文件会溢出
    final  FilePickerResult? result =  await FilePicker.platform.pickFiles(allowMultiple:true);
    
    if (result!=null) {
      List<PlatformFile> files = result.files;
      for(var file in files){
        var name = file.name.replaceFirst(RegExp(r'\.\w+$'), "");
        await filter(name,file.xFile);
      }
    }
  }
  //assets相对路径
  static String assetsRelativePath(String path) => path.substring(path.indexOf("assets/")+7);
  
  //复制文件
  static copyFile(String name,String dir,{bool overwrite=true,}) async {
    final srcFile = File(name);
    var toFile = RegExp(r"\.\w+$").hasMatch(dir) ? dir : "$dir/${srcFile.baseName}";
    final targetFile = File(toFile);
    // 检查是否需要覆盖
    if (await targetFile.exists() && !overwrite) {
      print("文件已存在，跳过：$dir");
      return;
    }
    //创建目录 
    final targetDir = targetFile.parent;
    if (!await targetDir.exists()) await targetDir.create(recursive: true);
    //写入主文件
    
    await targetFile.writeAsBytes(srcFile.readAsBytesSync());
  }

  static Future<void> copyPath(String sourceDirPath,String targetDirPath,{ bool overwrite = true,RegExp? skipPattern,}) async{
       // 1. 校验源目录
    final sourceDir = Directory(sourceDirPath);
    if (!await sourceDir.exists()) {
      throw Exception("源目录不存在：$sourceDirPath");
    }

    // 2. 创建目标目录（如果不存在）
    final targetDir = Directory(targetDirPath);
    if (!await targetDir.exists()) {
      await targetDir.create(recursive: true);
      print("创建目标目录：$targetDirPath");
    }

    // 3. 遍历源目录中的所有实体
    final entities = sourceDir.list(recursive: false, followLinks: false);
    await for (final entity in entities) {
      final entityName = p.basename(entity.path);
      
      // 跳过符合条件的文件/目录
      if (skipPattern != null && skipPattern.hasMatch(entityName)) {
        print("跳过：${entity.path}");
        continue;
      }

      // 计算目标路径
      final targetPath = p.join(targetDirPath, entityName);

      if (entity is File) {
        // 4. 复制文件（使用流复制大文件）
        await copyFile(
          entity.path, targetPath,
          overwrite: overwrite,
        );
      } else if (entity is Directory) {
        // 5. 递归复制子目录
        await copyPath(
          entity.path,
          targetPath,
          overwrite: overwrite,
          skipPattern: skipPattern,
        );
      }
    }

  }

  static get tmpDir => System.tmpDir;
  static get assetsDir =>   assetsDirectory("assets/").path;
  //构建文件
  static Future<File> buildDtt(String name,String data,List<String> files) async{
    //创建目录 
    final targetDir = Directory(p.join(tmpDir,name));
    if (!await targetDir.exists()) await targetDir.create(recursive: true);
    //写入主文件
    final targetFile = File("$tmpDir$name/txt/$name.txt");
    await targetFile.parent.create();
    await targetFile.writeAsString(data);
     //其他文件
    // ignore: avoid_function_literals_in_foreach_calls
    files.forEach((path) async => await copyFile(path,"${targetDir.path}/${assetsRelativePath(path)}") );
    // 压缩返回
    var rt=File("$tmpDir$name.dtt");
    await ZipUtils.compressDirectory(
      sourceDirPath: targetDir.path,
      targetZipPath: rt.path,
      skipHiddenFiles: true,
    );
    return rt;
  }

  //导入dtt文件
  static Future<void> importDtt(String file,{bool overwrite=false}) async{
    var name = File(file).name;
     //解压到目录 
    final targetDir = Directory(tmpDir+name);
    await ZipUtils.decompressZip(
      zipFilePath: file,
      targetDirPath: targetDir.path,
      overwrite: true, // 覆盖已存在的文件
    );
    await copyPath(targetDir.path,assetsDir,overwrite: overwrite);
    msg("导入完成！");
  }

  static void rename(String type,String oldName, String newName) {
      var file = File(getWholeName("assets/$type",oldName));
      file.rename(file.path.replaceFirst(oldName, newName));
  }
  static AndroidChannel android = AndroidChannel();


}

class AndroidChannel {
  static const platform = MethodChannel('app/file_provider'); // 与原生一致
  Future<String> openFile(File file) async{
      final String rt = await platform.invokeMethod(
          'openFile',
          {'path': file.path},
      );
      return rt;
  }
  // 将你的文件路径转为 content:// URI
  Future<String> convertToContentUri(File file) async {
      
      try {
        final String? contentUri = await platform.invokeMethod(
          'get_content_uri',
          {'file_path': file.path}, // 传入文件的物理路径（如 /data/data/com.example.app/files/test.pdf）
        );
        print("生成的 content:// 路径：$contentUri");
        // 示例输出：content://com.example.app.fileprovider/my_files/test.pdf
        return contentUri??"";
      } on PlatformException catch (e) {
        print("生成失败：${e.message}");
        return "";
      }
  }
}

extension on File {
  // ignore: unused_element
  String get exName => path.substring(path.lastIndexOf('.')).toLowerCase();
  String get baseName => path.split(Platform.pathSeparator).last;
  String get name => baseName.substring(0,baseName.lastIndexOf('.'));
}